﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using DG.Common.EF.WPF;
using TCC.ControleFluxoDeCaixa.Model.Contas;
using TCC.ControleFluxoDeCaixa.Model.Gerenciadores;

namespace TCC.ControleFluxoDeCaixa.Model.Fluxo.Credito
{
    [Table("ContaCredito")]
    public class ContaCredito : ContaFinanceira
    {
        private decimal _valorLimite;

        [Required]
        [Index(IsUnique = true)]
        [MaxLength(16)]
        [MinLength(16)]
        public string Numero { get; set; }
        [MaxLength(3)]
        [MinLength(3)]
        [Required]
        [Display(Name = @"Digito Verificador",Prompt =@"XXX", Description=@"Normalmente está localizado atrás do cartão")]
        [FilteredAtributte(false)]
        public string DigitoVerificador { get; set; }
        [Required]
        public virtual BandeiraCredito Bandeira { get; set; }
        [Required]
        [Display(Name = @"Conta Vinculada",Description = @"Trata-se da conta de bancária vinculada ao cartão")]
        public virtual ContaFinanceiraBancaria ContaVinculada { get; set; }
        [Required]
        [Display(Name = @"Valor da Anuidade")]
        [FilteredAtributte(false)]
        public decimal ValorAnuidade { get; set; }

        [Required]
        [Display(Name = @"Valor do Limite")]
        [FilteredAtributte(false)]
        public decimal ValorLimite
        {
            get { return _valorLimite; }
            set
            {
                if (value == _valorLimite) return;
                _valorLimite = value;
                OnPropertyChanged("ValorLimite");
            }
        }

        [Required]
        [Display(Name = @"Titular do cartão")]
        [FilteredAtributte(false)]
        public string TitularDoCartao { get; set; }
        [Required]
        [FilteredAtributte(false)]
        public DateTime Validade { get; set; }
        [Required]
        [Display(Name = @"Dia do vencimento",Description = @"Data na qual a fatura do cartão de crédito vence")]
        public int DiaDoVencimento { get; set; }
        [Required]
        [Display(Name = @"Qtd/Dias para o Fechamento",Description = @"Quantidade de dias entre o vencimento e o fechamento.")]
        [FilteredAtributte(false)]
        public virtual int QtdDiasPeriodoFechamento { get; set; }
        public virtual ICollection<FaturaCredito> Faturas { get; set; } 

        public Lancamento LancamentoCartaoCredito(Lancamento lancamento,decimal valorTotal, 
            DateTime dataCompra, int qtdParcelas)
        {

            decimal resto;
            var valorParcela = CalcularValorParcela(valorTotal, qtdParcelas, out resto);
            var dataBaseVencimento = DefinirInicioDaCobranca(dataCompra);
            int contador;


            var dif = lancamento.Movimentos.Count - qtdParcelas;
            for (var i = 1; i <= dif; i++)
            {
                lancamento.Movimentos.Remove(lancamento.Movimentos.Last());
            }
            var movs = lancamento.Movimentos.ToArray();

            for (contador = 1; contador <= qtdParcelas; contador++)
            {
                Movimento m;
                if (contador <= movs.Length)
                    m = movs[contador - 1];
                else
                {
                    m = new Movimento();
                    lancamento.Movimentos.Add(m);
                }
                
                m.Lancamento = lancamento;
                m.DataDoMovimento = GerenciadorDeDatas.GetInstance().DiaUtil(dataBaseVencimento);
                m.TipoDeMovimento = TipoDeMovimento.Despesa;
                m.ValorAbsoluto = (contador < 2 ? (valorParcela + resto) : (valorParcela));
                m.Historico = "PARCELA: " + (qtdParcelas == 1  ? "Única" : ((contador) + " DE " + qtdParcelas)) + " - " + lancamento.Nome;
                m.Conta = this;
                dataBaseVencimento = dataBaseVencimento.AddMonths(1);
            }
            return lancamento;
        }
        public Lancamento LancamentoCartaoCredito(decimal valorTotal,
            Categoria categoria,DateTime dataCompra,int qtdParcelas,string descricao)
        {
            
            var lancamento = new Lancamento
            {
                Categoria = categoria,
                DataDoLancamento = dataCompra,
                Nome = descricao,
                Usuario = AutenticadorDeSessao.GetInstance().CurrentSession.Usuario
                
            };

            return LancamentoCartaoCredito(lancamento,valorTotal,dataCompra,qtdParcelas);
        }
        

        private static decimal CalcularValorParcela(decimal valorTotal, int qtdParcelas, out decimal resto)
        {
            decimal valorParcela;
            if (qtdParcelas == 0)
            {
                valorParcela = valorTotal;
                resto = 0;
                return valorParcela;
            }
            var valor = (valorTotal/qtdParcelas);
            valor *= 100;
            valor = Math.Floor(valor);
            valorParcela = (valor/100);
            resto = (valorTotal - (valorParcela*qtdParcelas));
            return valorParcela;
        }

        private DateTime DefinirInicioDaCobranca(DateTime dataCompra)
        {
            //Calcula o fechamento da fatura.
            var fechamento = ObterDiaFechamentoFatura(dataCompra);
            var diaFecFatura = fechamento.Day;
            const int janeiro = 1;
            const int fevereiro = 2;
            //Defini em qual mês a cobrança será iniciada.
            if (DiaDoVencimento >= diaFecFatura)
            {
                return dataCompra.Day >= diaFecFatura
                    ? new DateTime((dataCompra.Month == 12 ? dataCompra.Year + 1 : dataCompra.Year), (dataCompra.Month == 12 ? janeiro : dataCompra.Month + 1), DiaDoVencimento) 
                    : new DateTime(dataCompra.Year, (dataCompra.Month), DiaDoVencimento);
            }

            return dataCompra.Day < diaFecFatura
                ? new DateTime((dataCompra.Month == 12 ? dataCompra.Year + 1 : dataCompra.Year), 
                    (dataCompra.Month == 12 ? janeiro : dataCompra.Month + 1), DiaDoVencimento)
                : new DateTime((dataCompra.Month == 12 ? dataCompra.Year + 1 : dataCompra.Year), 
                    (dataCompra.Month == 12 ? fevereiro : dataCompra.Month + 2), DiaDoVencimento);
        }

        public DateTime ObterDiaFechamentoFatura(DateTime dataCompra)
        {
            var getData = GerenciadorDeDatas.GetInstance();
            const int janeiro = 1;
            const int fevereiro = 2;
            if (dataCompra.Day >= DiaDoVencimento)
            {
                var vencimento = new DateTime((dataCompra.Month == 12 ? dataCompra.Year + 1 : dataCompra.Year), 
                    dataCompra.Month == 12 ? janeiro : (dataCompra.Month + 1), DiaDoVencimento);
                vencimento = GerenciadorDeDatas.GetInstance().DiaUtil(vencimento);
                var fechamento = vencimento.AddDays(-QtdDiasPeriodoFechamento);

                if (fechamento > dataCompra) return fechamento;

                vencimento = new DateTime((dataCompra.Month == 12 ? dataCompra.Year + 1 : dataCompra.Year), 
                    dataCompra.Month == 12 ? fevereiro : (dataCompra.Month + 2), DiaDoVencimento);
                vencimento = getData.DiaUtil(vencimento);
                fechamento = vencimento.AddDays(-QtdDiasPeriodoFechamento);
                return fechamento;

            }
            //if (dataCompra.Day <= DiaDoVencimento)
            {
                var vencimento = new DateTime(dataCompra.Year, dataCompra.Month, DiaDoVencimento);
                vencimento = GerenciadorDeDatas.GetInstance().DiaUtil(vencimento);
                var fechamento = vencimento.AddDays(-QtdDiasPeriodoFechamento);

                if (fechamento > dataCompra) return fechamento;

                vencimento = new DateTime((dataCompra.Month == 12 ? dataCompra.Year + 1 : dataCompra.Year), 
                    (dataCompra.Month == 12 ? janeiro : dataCompra.Month + 1), DiaDoVencimento);
                vencimento = getData.DiaUtil(vencimento);
                fechamento = vencimento.AddDays(-QtdDiasPeriodoFechamento);
                return fechamento;
            }
        }

        public override string ToString()
        {
            return Nome;
        }
    }
}
